﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace MultiClassDBA.ChannelBuilder
{


    class ChannelViewPanel : Panel
    {
        List<ChannelGraphNode> nodes;
        //List<List<String>> dispGrid;
        String[,] dispGrid;
        int[] columnCount;
        Dictionary<int[],int[]> connections;
        Dictionary<ChannelGraphNode, int[]> nodePositions;
        public ChannelViewPanel(List<ChannelGraphNode> nodes)
        {
            nodePositions = new Dictionary<ChannelGraphNode, int[]>();
            connections = new Dictionary<int[],int[]>();
            dispGrid = new String[150,100];
            columnCount = new int[150];
            this.nodes = new List<ChannelGraphNode>();
            foreach (ChannelGraphNode n in nodes)
                this.nodes.Add(n);
            this.Paint += new PaintEventHandler(channel_paint);
            
        }

        private void channel_paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            dispGrid = new String[150, 100];
            columnCount = new int[150];

            //find the depth we should display each node at
            int changed = 1;
            while (changed != 0)
            {
                changed = 0;
                foreach (ChannelGraphNode n in nodes)
                {
                    foreach (String s in n.inTables)
                        foreach (ChannelGraphNode n1 in nodes)
                            if (n1.outTables.Contains(s) && n1.outTableRev <= n.inTableRev)
                            {
                                int oldDepth = n.depth;
                                n.depth = n1.depth + 1;
                                if (oldDepth != n.depth)
                                    changed++;
                            }
                }

            }

            //make sure the preceding code did its job
            foreach (ChannelGraphNode n in nodes)
                System.Console.WriteLine(n.name + ": " + n.depth);

            nodePositions = new Dictionary<ChannelGraphNode, int[]>();
            connections = new Dictionary<int[], int[]>();
            //add 5 columns
            for (int i = 0; i < 5; i++)
            {
                foreach(ChannelGraphNode n in nodes)
                    if (n.depth == i)
                    {
                        //print intables if they aren't the output of something else
                        int startIndex = columnCount[i*3];
                        foreach(String inTable in n.inTables)
                        {
                            bool add = true;
                            foreach(ChannelGraphNode n1 in nodes)
                                if (n1.outTables.Contains(inTable) && n1.outTableRev <= n.inTableRev)
                                {
                                    add = false;
                                    //TO DO: add command to draw line from previous transform to current transform
                                    int[] from = n1.outTablePosition[inTable];
                                    if (!connections.ContainsKey(from))
                                        connections.Add(from, null);
                                }

                            if (add)
                            {
                                dispGrid[i * 3,columnCount[i*3]] = inTable;
                                //add command to draw line from inTable to Transfrom
                                connections.Add(new int[]{i*3,columnCount[i*3]},null);//we haven't determined the position of the transform name yet
                                columnCount[i * 3]++;
                            }
                            
                        }

                        int endIndex = columnCount[i*3];
                        
                        //print Transform name
                        dispGrid[i*3+1,(startIndex+endIndex)/2] = "    " + n.name;
                        columnCount[i * 3 + 1]++;
                        nodePositions.Add(n, new int[] { i * 3 + 1, (startIndex + endIndex) / 2 });

                        Dictionary<int[], int[]> connectionsCopy = new Dictionary<int[], int[]>();
                        foreach (KeyValuePair<int[], int[]> p in connections)
                            connectionsCopy.Add(p.Key,p.Value);

                        foreach (int[] key in connectionsCopy.Keys)//fill in the nulls we created earlier when we didnt know where we were going to
                            if (connections[key] == null)      //put the transform name
                                connections[key] = new int[] { i * 3 + 1, (startIndex + endIndex) / 2 };

                        //print outTables if they're not going to be used by something else
                        columnCount[i * 3+2] = startIndex;
                        foreach (String outTable in n.outTables)
                        {
                            bool add = true;
                            //let's try printing all of them...
                            /*
                            foreach (ChannelGraphNode n1 in nodes)
                                if (n1.inTables.Contains(outTable) && n1.inTableRev >= n.outTableRev)
                                    add = false;
                            */

                            if (add)
                            {
                                dispGrid[i * 3+2, columnCount[i * 3+2]] = outTable;
                                if(!n.outTablePosition.ContainsKey(outTable))
                                    n.outTablePosition.Add(outTable, new int[] { i * 3 + 2, columnCount[i * 3 + 2] });
                                else
                                    n.outTablePosition[outTable] = new int[] { i * 3 + 2, columnCount[i * 3 + 2] };
                                connections.Add(new int[] { i * 3 + 1, (startIndex + endIndex) / 2 },
                                    new int[] { i * 3 + 2, columnCount[i * 3 + 2] });
                                columnCount[i * 3+2]++;
                            }
                        }
                        
                        columnCount[i * 3]++;
                    }
            }

            foreach (KeyValuePair<int[], int[]> pair in connections)
            {
                int startyOffset = 0;
                int endyOffset = 0;
                if (pair.Key[0] % 3 == 1)
                    startyOffset = 10;
                if (pair.Value[0] % 3 == 1)
                    endyOffset = 10;
                g.DrawLine(new Pen(new SolidBrush(Color.Gray)), new Point(120 + pair.Key[0] * 140, 17 + pair.Key[1] * 25 + startyOffset),
                    new Point(10 + pair.Value[0] * 140, 17 + pair.Value[1] * 25 + endyOffset));
            }

            Font f = new Font("Verdana", 10);
            

            for (int x = 0; x < 15; x++)
                for (int y = 0; y < 15; y++)
                {
                    Brush b = new SolidBrush(Color.Black);
                    int yOffset = 0;
                    if (x % 3 == 1)
                    {
                        yOffset = 10;
                        b = new SolidBrush(Color.DarkBlue);
                    }
                    String s = dispGrid[x, y];
                    if (s != null && s.Length > 14)
                        s = s.Substring(0, 14);
                    if(s != null)
                        g.FillRectangle(new SolidBrush(Color.FromArgb(157, 255, 255, 255)), new Rectangle(10 + x * 140, 10 + y * 25 + yOffset,
                            110, 18));

                    g.DrawString(s, f, b, 10 + x * 140, 10 + y * 25 + yOffset);
                }
            //g.DrawString(current.name,f,b,150,(columnPositions[0]/2)*20);
            //foreach (ChannelGraphNode cn in nodes)


            //g.DrawString("Hi", new Font("Verdana", 10), new SolidBrush(Color.Black), 10, 10);

        }
    }

    public class ChannelGraphNode
    {
       
        public String name;
        public List<String> inTables;
        public int inTableRev;
        public List<String> outTables;
        public int outTableRev;
        public int depth;
        public Dictionary<String, int[]> outTablePosition;

        public ChannelGraphNode(String name)
        {
            this.name = name;
            outTablePosition = new Dictionary<string, int[]>();
            inTables = new List<String>();
            outTables = new List<String>();
        }

        public override int GetHashCode()
        {
            return name.GetHashCode() + inTableRev.GetHashCode() + inTables.GetHashCode();
        }
    }
}
